# JWT 鉴权中间件

from jose import jwt
from jose.exceptions import JWTError, ExpiredSignatureError
from datetime import datetime, timezone
from typing import Optional, List
from fastapi import Request, HTTPException, status, Depends
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response

from src.config.settings import get_settings
from src.utils.logger import app_logger as logger
from src.cores.exceptions import ResponseCode


class JWTAuthMiddleware(BaseHTTPMiddleware):
    """JWT鉴权中间件"""

    def __init__(self, app, exempt_paths: Optional[List[str]] = None):
        super().__init__(app)
        self.config = get_settings()
        # 默认白名单路径
        self.exempt_paths = exempt_paths or [
            "/",
            "/health",
            "/docs",
            "/redoc",
            "/openapi.json",
            "/static",
            "/favicon.ico",
            "/api/v1/user/login",
            "/api/v1/user/refresh",
        ]

    async def dispatch(self, request: Request, call_next) -> Response:
        """中间件处理逻辑"""
        
        logger.debug(f"JWT中间件处理请求: {request.method} {request.url.path}")

        # 检查是否为白名单路径
        if self._is_exempt_path(request.url.path):
            logger.debug(f"路径 {request.url.path} 在白名单中，跳过JWT验证")
            return await call_next(request)

        # 检查Authorization头
        auth_header = request.headers.get("Authorization")
        if not auth_header:
            return self._create_error_response(
                ResponseCode.TOKEN_MISSING.message, ResponseCode.TOKEN_MISSING.code
            )

        # 验证Bearer token格式
        if not auth_header.startswith("Bearer "):
            return self._create_error_response(
                "Authorization头格式错误，应为: Bearer <token>",
                ResponseCode.TOKEN_INVALID.code,
            )

        # 提取token
        token = auth_header.split(" ")[1]

        try:
            # 验证JWT token (JWT库会自动检查过期时间)
            payload = jwt.decode(
                token, self.config.SECRET_KEY, algorithms=[self.config.ALGORITHM]
            )
            
            # 检查token类型，只允许access token通过中间件
            token_type = payload.get("type")
            if token_type != "access_token":
                return self._create_error_response(
                    "无效的token类型，请使用access token",
                    ResponseCode.TOKEN_INVALID.code,
                )

            # 将用户信息添加到请求状态中
            request.state.user_id = payload.get("user_id")
            request.state.username = payload.get("username")
            request.state.user_info = payload
            request.state.refresh_token_id = payload.get("refresh_token_id")

            logger.info(
                f"用户 {payload.get('username', 'unknown')} 通过鉴权访问 {request.url.path}"
            )

        except ExpiredSignatureError:
            return self._create_error_response(
                ResponseCode.TOKEN_EXPIRED.message, ResponseCode.TOKEN_EXPIRED.code
            )
        except JWTError as e:
            logger.warning(f"JWT验证失败: {str(e)}")
            return self._create_error_response(
                ResponseCode.TOKEN_INVALID.message, ResponseCode.TOKEN_INVALID.code
            )
        except Exception as e:
            logger.error(f"鉴权中间件异常: {str(e)}")
            return self._create_error_response(
                "鉴权验证失败", ResponseCode.SYSTEM_ERROR.code
            )

        # 继续处理请求
        response = await call_next(request)
        return response

    def _is_exempt_path(self, path: str) -> bool:
        """检查路径是否在白名单中"""
        for exempt_path in self.exempt_paths:
            if path.startswith(exempt_path):
                return True
        return False

    def _create_error_response(self, message: str, code: int) -> JSONResponse:
        """创建错误响应"""
        return JSONResponse(
            status_code=200,  # 统一返回200状态码
            content={
                "code": code,
                "message": message,
                "data": None,
                "timestamp": datetime.now().isoformat(),
            },
        )


def add_jwt_auth_middleware(app, exempt_paths: Optional[List[str]] = None):
    """添加JWT鉴权中间件"""
    app.add_middleware(JWTAuthMiddleware, exempt_paths=exempt_paths)
    logger.info("JWT鉴权中间件已添加")


async def get_current_user_id(request: Request) -> int:
    """从请求中获取当前用户ID"""
    user_id = getattr(request.state, 'user_id', None)
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="用户未认证"
        )
    return user_id
